文章目录
标签:JavaScript 设计模式
前言:最近在学习Node.js,了解了node中的事件驱动机制,而相应的事件循环实现和设计模式中观察者相似,于是打算将观察者模式顺带学习一番。
定义
通过查阅书籍,以及一些其他文档,观察者模式的定义可以简述为以下几个步骤:
- 目标状态发生观察者感兴趣的改变
- 目标对象发送一个通知消息(怎样发送,或是通过什么发送呢)
- 目标对象调用每个观察者的更新方法
- 最后,当观察者不再对目标状态的更新感兴趣,则观察者将自动分离
角色及作用
- Subject (目标) 维护一系列观察者,方便添加或者删除观察者;
- Observer(观察者)为那些目标状态发生改变时需获得通知的对象(具体观察者?)提供一个更新接口;
- ConcreteSubject(具体目标) 状态发生改变时,向Observer发出通知,存储ConcreteObserver的状态;
- ConcreteObserver(具体观察者)存储一个ConcreteObserver的引用,实现更新接口,以使自身状态和目标状态保持一致。
以下实现一个观察者模式的组件
首先,模拟一个目标可能拥有的一系列Observer
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| function ObserverList() { this.observerlist = []; } ObserverList.prototype.Add = function (obj) { this.observerlist.push(obj); }; ObserverList.prototype.Empty = function () { this.observerlist.length = 0; }; ObserverList.prototype.Count = function () { return this.observerlist.length; }; ObserverList.prototype.Get = function (index) { if (index > -1 && index < this.observerlist.length) { return this.observerlist[index]; } }; ObserverList.prototype.Insert = function (obj, index) { let pointer = -1; if (index === 0) { this.observerlist.unshift(obj); pointer = index; } else if (index === this.observerlist.length) { this.observerlist.push(obj); pointer = index; } return pointer; }; ObserverList.prototype.IndexOf = function (obj, startIndex) { let pointer = -1, i = startIndex; while(i < this.observerlist.length) { if (this.observerlist[i] === obj) { pointer = i; } i++; } return pointer; }; ObserverList.prototype.RemoveIndexAt = function (index) { if (index === 0) { this.observerlist.shift(); } else if (index === this.observerlist.length - 1) { this.observerlist.pop(); } }; function extend(obj, extention) { for (let key in obj) { extention[key] = obj[key]; } };
|
接下来,来模拟目标(Subject)和在观察者列表上添加。删除或通知观察者的能力
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| function Subject(){ this.observers = new ObserverList(); } Subject.prototype.AddObserver = function (observer) { this.observers.Add(observer); }; Subject.prototype.RemoveObserver = function (observer) { this.observers.RemoveIndexAt(this.observers.IndexOf(observer, 0)); }; Subject.prototype.Notify = function (context) { let observerCount = this.observers.Count(); for (let i = 0; i < observerCount; i++) { this.observers.Get(i).Update(context); } };
|
然后定义一个框架来创建新的Observer
1 2 3 4 5 6 7
| function Observer() { this.Update = () => { } }
|
上面实现了一个观察者模式,接下来通过一个实例程序,学习怎样使用观察者模式:
- 用于向页面添加新可见的CheckBox按钮;
- 控制CheckBox,将充当一个目标,通知其他CheckBox需要进行检查;
- 用于添加新CheckBox的容器
实现代码如下:
1 2 3
| <button id="addNewObserver">Add New Observer checkbox</button> <input type="checkbox" id="mainCheckbox"> <div id="observerContainer"></div>
|
下面是样例代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| var controlCheckbox = document.getElementById('mainCheckbox'), addBtn = document.getElementById('addNewObserver'), container = document.getElementById('observerContainer'); extend(new Subject(), controlCheckbox); controlCheckbox["onclick"] = new Function("controlCheckbox.Notify(controlCheckbox.checked)"); addBtn["onclick"] = AddNewObserver; function AddNewObserver() { var check = document.createElement("input"); check.type = "checkbox"; extend(new Observer(), check); check.Update = function (value) { this.checked = value; }; controlCheckbox.AddObserver(check); container.appendChild(check); }
|
以上就是观察者模式的简单实现和使用,主要弄清楚目标,观察者,具体目标,具体观察者这四者之间的关系,以及弄清它们之间的调用的关系。总体说来还是比较容易理解。
主要参考:JavaScript设计模式 [美] Addy Osnabi 著